package cn.mayaslight.common.proxy;

import java.lang.annotation.Annotation;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity;

import com.sun.xml.internal.ws.handler.HandlerException;

import cn.mayaslight.common.annotation.HttpWithEntity;
import cn.mayaslight.common.annotation.HttpWithHeader;
import cn.mayaslight.common.annotation.HttpWithParam;
import cn.mayaslight.common.common.BaseConsts;
import cn.mayaslight.common.handler.LocalHttpClient;
import cn.mayaslight.common.http.RequestBuilderPack;
import cn.mayaslight.common.param.IParamIn;
import cn.mayaslight.common.utils.ReflectUtils;

public class CallerProxy<A extends Annotation, T> {
	
	private RequestBuilder requestBuilder;
	
	private ResponseHandler<T> handler;
	
	private HttpUriRequest httpUriRequest;
	
	private CallerProxy() {
		//TODO
	}
	
	public static <A extends Annotation, T> CallerProxy<A, T> create(RequestBuilderPack<T> builder) {
		CallerProxy<A, T> callerProxy = new CallerProxy<A, T>();
		callerProxy.requestBuilder = builder.getRequestBuilder();
		callerProxy.handler = builder.getResponseHandler();
		return callerProxy;
	}
	
	public CallerProxy<A, T> addHeader(IParamIn param){
		if(param != null){
			Map<String, Map<String, Object>> headerMap = ReflectUtils.getProperties(param.getClass(), param, HttpWithHeader.class, true);
			for(Map.Entry<String, Map<String, Object>> me : headerMap.entrySet()){
				Map<String, Object> properties = me.getValue();
				Object value = properties.get(me.getKey());
				if(value instanceof Header){
					requestBuilder = requestBuilder.addHeader((Header)value);
				}else{
					Object annoValue = properties.get("value");
					String key = me.getKey();
					if(annoValue != null && StringUtils.isNotBlank(annoValue.toString())){
						key = annoValue.toString();
					}
					requestBuilder = requestBuilder.addHeader(key, value.toString());
				}
			}
		}
		return this;
	}
	
	public CallerProxy<A, T> addParameter(IParamIn param){
		if(param != null){
			Map<String, Map<String, Object>> paramMap = ReflectUtils.getProperties(param.getClass(), param, HttpWithParam.class, true);
			for(Map.Entry<String, Map<String, Object>> me : paramMap.entrySet()){
				Map<String, Object> properties = me.getValue();
				Object value = properties.get(me.getKey());
				Object annoValue = properties.get("value");
				String key = me.getKey();
				if(annoValue != null && StringUtils.isNotBlank(annoValue.toString())){
					key = annoValue.toString();
				}
				requestBuilder = requestBuilder.addParameter(key, value.toString());
			}
		}
		return this;
	}
	
	public CallerProxy<A, T> setEntity(IParamIn param) {
		if(param != null){
			Map<String, Map<String, Object>> paramMap = ReflectUtils.getProperties(param.getClass(), param, HttpWithEntity.class, true, "type", "charset");
			if(paramMap.size() == 0){
				return this;
			} else if(paramMap.size() > 1) {
				throw new HandlerException("传入的类有多个@HttpWithEntity注解!");
			}
			for(Map.Entry<String, Map<String, Object>> me : paramMap.entrySet()){
				Map<String, Object> properties = me.getValue();
				Object value = properties.get(me.getKey());
				Object charset = properties.get("charset");
				Object type = properties.get("type");
				HttpEntity entity;
				if(type != null && StringUtils.isNotBlank(type.toString())){
					entity = new StringEntity(value.toString(), charset != null && StringUtils.isNotBlank(charset.toString()) ? charset.toString() : BaseConsts.Constants.CHARSET);
				}else{
					throw new HandlerException("未知Entity");
				}
				requestBuilder.setEntity(entity);
			}
		}
		return this;
	}
	
	public CallerProxy<A, T> build() {
		httpUriRequest = requestBuilder.build();
		return this;
	}
	
	public HttpResponse execute() {
		return LocalHttpClient.execute(httpUriRequest);
	}
	
	public T executeWithHandler() {
		return LocalHttpClient.execute(httpUriRequest, handler);
	}
	
}
